#include <fstream>
#include <inttypes.h>
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include "analyzer.h"
#include "logger.h"
#include "util.h"
#include "resultsfilter.h"

using namespace std;

#define NO_VAL			-1
#define DATA_SPACING	11	// Number of spaces per data item

class gnuplotWriter
{
public:
	gnuplotWriter();
	~gnuplotWriter();

	/*
	 * Writes Data to the specified dataFile. Calls all other
	 * functions to make this possible
	 * @return true if all went well.
	 */
	bool writeGnuplotData();

	//--------------Variables-----------------//
	long double	normalize;	// Normalize data to this value

	bool		repVal;		// Output a representative value for each line

	fstream		file_op;	// outstream
	string		outfile;	// File to write data to

	u_int		maxVal;

	vector<analyzerResultList>	fullResultList;

private:
	/*
	 * Checks to make sure the values given are error free
	 * @return true if all is good
	 */
	bool checkError();

	/*
	 * Finds the largest session number in all of our log files.
	 */
	void findMaxLogValue ();

	/*
	 * Writes the sessions names to the dataFile
	 */
	void writeNames();

	/*
	 * Checks if the last sessions last data point is larger
	 * than those of the other provided sessions
	 */
	bool lastLarger();

	/*
	 * Checks if the representative data point for the last
	 * is larger than the others
	 */
	bool repLastLarger();

	/*
	 * Writes data to the dataFile
	 */
	void writeData();

	/*
	 * Space the data in the datafiles according to the value
	 * specified by DATA_SPACING. 
	 * @param location The column number of the data
	 * @param max The last column number of the data
	 * @param xVal The xValue written to the datafile
	 * @param yVal The yValue written to the logfile at column location
	 */
	string autoSpace (long double location, int max, long double xVal,
					  long double yVal);
};

gnuplotWriter::gnuplotWriter()
{
	repVal		= NO_VAL;
	normalize	= 0;
	outfile		= "";
}

gnuplotWriter::~gnuplotWriter()
{
}

bool gnuplotWriter::writeGnuplotData()
{
	if (!checkError())
		return false;

	findMaxLogValue();

	file_op.open(outfile.c_str(),ios::out);

	writeNames();

	writeData();

	file_op.close();

	return true;
}

bool gnuplotWriter::checkError()
{
	if (repVal == NO_VAL)
	{
		ERROR("Bad representative value")
		return false;
	}
	if (normalize == 0)
	{
		ERROR("Cannot normalize to zero")
		return false;
	}
	if (outfile.compare("") == 0)
	{
		ERROR("Empty output filename")
		return false;
	}
	return true;
}

void gnuplotWriter::findMaxLogValue ()
{
	maxVal = 0;
	for (u_int i = 0; i < fullResultList.size(); i++)
	{
		if (fullResultList[i].size() > maxVal)
			maxVal = fullResultList[i].size();
	}
}

void gnuplotWriter::writeNames()
{
	file_op << "#PacketNum  ";
	for (uint sess = 0; sess < fullResultList.size(); sess++)
	{
		file_op << fullResultList[sess].filename << 
			fullResultList[sess].sessionNumber;

		// Add correct Spacing
		for (int k = fullResultList[sess].filename.size() +1; 
				k <= (DATA_SPACING -1); k++)
			file_op << " ";
	}
	file_op << endl;
}

void gnuplotWriter::writeData ()
{
	for (u_int i = 0; i < fullResultList.size(); i++)
	{
		int count = 0;

		// Get the individual result list for our session
		analyzerResultList *res = &(fullResultList[i]);
		if (res->size() == 0)
			continue;

		if (normalize != -1) // Normalization Requested
		{
			// Find the interval by which to increase our xValues
			long double interval = normalize / ( res->size() - 1);
			for (long double j = 0; j <= normalize; j += interval)
			{
				// Write normalized data to log
				file_op << autoSpace(i, fullResultList.size(), j, (*res)[count++]);
			}
		}
		else // No Normalization Please
		{
			for (long double j = 0; j < res->size()-1; j++)
			{
				file_op << autoSpace(i, fullResultList.size(), j, (*res)[count++]);
			}
		}
	}

	// TODO: Remove this for longterm use!
	if (repLastLarger())
		file_op << "#lastLarger" << endl;
	else
		file_op << "#lastSmaller" << endl;
}

bool gnuplotWriter::lastLarger ()
{
	// Not enough data to analyze
	if (fullResultList.size() < 2)
		return false;

	long double maxVal = 0;
	for (u_int i = 0; i < fullResultList.size(); i++)
	{
		analyzerResultList res = fullResultList[i];
		long double lastVal = res.size() - 1;

		if (res[lastVal] > maxVal)
		{
			if (i == (fullResultList.size() -1))
				return true;
			maxVal = res[lastVal];
		}
	}
	return false;
}

bool gnuplotWriter::repLastLarger ()
{
	// Not enough data to analyze
	if (fullResultList.size() < 2)
		return false;

	long double maxVal = 0;
	for (u_int i = 0; i < fullResultList.size(); i++)
	{
		getRepVal g;
		analyzerResultList rep = g.doFilter(fullResultList[i]);
		if (rep.size() > 0 && rep[0] > maxVal)
		{
			if (i == (fullResultList.size() - 1))
				return true;
			maxVal = rep[0];
		}
	}
	return false;
}

string gnuplotWriter::autoSpace (long double location, int max,
								 long double xVal, long double yVal)
{
	ostringstream out;
	out << xVal;
	int strLen = out.str().size();

	// Add Beginning Whitespace
	for (int j = strLen; j <= DATA_SPACING; j++)
		out << " ";
	for (long double i = 0; i < location; i++)
		out << "-          ";
	int tmpLen = out.str().size();

	// Add the actual Value
	out << yVal;

	// Add Ending Whitespace
	strLen = out.str().size() - tmpLen;
	for (int j = strLen; j <= DATA_SPACING; j++)
		out << " "; for (long double i = location + 1; i < max; i++)
		out << "-          ";
	out << "\n";
	return out.str();
}

